package com.budwk.app.sys.services.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSONObject;
import com.budwk.app.common.component.DictComponent;
import com.budwk.app.common.config.AppException;
import com.budwk.app.exception.ServiceException;
import com.budwk.app.sys.models.Sys_dict;
import com.budwk.app.sys.services.SysDictService;
import com.budwk.app.sys.vo.SysDictVO;
import com.budwk.starter.common.constant.RedisConstant;
import com.budwk.starter.database.service.BaseServiceImpl;
import com.budwk.starter.security.utils.SecurityUtil;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.nutz.aop.interceptor.async.Async;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.util.cri.SqlExpressionGroup;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings;
import org.nutz.plugins.wkcache.annotation.CacheDefaults;
import org.nutz.plugins.wkcache.annotation.CacheRemoveAll;
import org.nutz.plugins.wkcache.annotation.CacheResult;

import java.util.*;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

/**
 * @author wizzer@qq.com
 */
@Slf4j
@IocBean(args = {"refer:dao"})
@CacheDefaults(cacheName = RedisConstant.WKCACHE + "shequ.sys_dict", isHash = false, cacheLiveTime = RedisConstant.WKCACHE_TIMEOUT)
public class SysDictServiceImpl extends BaseServiceImpl<Sys_dict> implements SysDictService {
    public SysDictServiceImpl(Dao dao) {
        super(dao);
    }

    @Inject("taskQueryExecutor")
    private ThreadPoolExecutor taskQueryExecutor;

    @Override
    @CacheResult
    public List<Sys_dict> getSubListByCode(String code) {
        Sys_dict dict = this.fetch(Cnd.where("code", "=", code));
        return dict == null ? new ArrayList<>() : this.query(Cnd.where("parentId", "=", Strings.sNull(dict.getId())).asc("location"));
    }

    /**
     * 通过父id获取下级列表
     *
     * @param id ID
     * @return
     */
    @Override
    @CacheResult
    public List<Sys_dict> getSubListById(String id) {
        return this.query(Cnd.where("parentId", "=", Strings.sNull(id)).asc("location"));
    }


    @Override
    @Aop(TransAop.READ_COMMITTED)
    public void save(Sys_dict dict, String pid) {
        if (StringUtils.isEmpty(dict.getCode())) {
            throw new AppException("字典编码不能为空！");
        }
        String code = dict.getCode().trim();
        Sys_dict sysDict = this.fetch(Cnd.where(Sys_dict::getCode, "=", code));
        if (sysDict != null) {
            throw new AppException("该字典编码已被使用，请重新输入！");
        }
        dict.setCreatedBy(SecurityUtil.getUserId());
        dict.setCreatedAt(System.currentTimeMillis());
        String path = "";
        if (!Strings.isEmpty(pid)) {
            Sys_dict pp = this.fetch(pid);
            path = pp.getPath();
        }
        dict.setPath(getSubPath("sys_dict", "path", path));
        dict.setParentId(pid);
        dao().insert(dict);
        if (!Strings.isEmpty(pid)) {
            this.update(Chain.make("hasChildren", true), Cnd.where("id", "=", pid));
        }
    }

    @Override
    @Aop(TransAop.READ_COMMITTED)
    public void deleteAndChild(Sys_dict dict) {
        //dao().execute(Sqls.create("delete from shequ.sys_dict where path like @path").setParam("path", dict.getPath() + "%"));
        //if (!Strings.isEmpty(dict.getParentId())) {
        //    int count = count(Cnd.where("parentId", "=", dict.getParentId()));
        //    if (count < 1) {
        //        dao().execute(Sqls.create("update shequ.sys_dict set hasChildren=0 where id=@pid").setParam("pid", dict.getParentId()));
        //    }
        //}

        // wzy 2023-10-20 改写字典表删除方法 之前通过path判断的会造成误删
        List<String> deleteIdList = Lists.newArrayList(dict.getId());
        deleteIdList.addAll(getAllSubId(dict.getId()));

        delete(deleteIdList);
    }

    @Override
    @CacheRemoveAll
    @Async
    public void cacheClear() {

    }

    @Override
    public List<SysDictVO> getDictTree(Sys_dict queryDict) {
        // 这个逻辑是查询第一级然后将剩下的数据都查询出来
        Cnd cnd = Cnd.NEW();
        if (StringUtils.isNotBlank(queryDict.getCode())) cnd.and("code", "=", queryDict.getCode());
        List<Sys_dict> list = query(cnd);

        List<SysDictVO> resultList = org.apache.commons.compress.utils.Lists.newArrayList();
        for (Sys_dict sysDict : list) {
            SysDictVO vo = new SysDictVO();
            BeanUtil.copyProperties(sysDict, vo);
            vo.setLabel(sysDict.getName());
            popularChildren(vo);
            resultList.add(vo);
        }

        return resultList;
    }

    @Override
    public List<Sys_dict> listDictByName(String dictName) {
        if (StringUtils.isEmpty(dictName)) {
            throw new AppException("缺少请求参数！");
        }
        Sys_dict sysDict = this.fetch(Cnd.where(Sys_dict::getName, "=", dictName));
        if (sysDict == null) {
            throw new AppException("请联系管理员先添加数据字典项！");
        }
        List<Sys_dict> list = this.query(Cnd.where(Sys_dict::getParentId, "=", sysDict.getId()));
        return list;
    }

    @Override
    public List<SysDictVO> listDictByCode(String dictCode) {
        if (StringUtils.isEmpty(dictCode)) {
            throw new AppException("缺少请求参数！");
        }
        Sys_dict sysDict = this.fetch(Cnd.where(Sys_dict::getCode, "=", dictCode));
        if (sysDict == null) {
            throw new AppException("请联系管理员先添加数据字典项！");
        }
        // 这些数据是有重孙数据的
        List<String> grandchildCode = DictComponent.getGrandchildCode();
        for (String code : grandchildCode) {
            if (code.equals(dictCode)) {
                return getAllChildRens(sysDict);
            }
        }
        // 没有子孙数据
        List<Sys_dict> sysDicts = listChildRen(sysDict.getId());
        List<SysDictVO> result = new ArrayList<>();
        if (sysDicts.size() > 0) {
            sysDicts.forEach(e -> {
                SysDictVO sysDictVo = new SysDictVO();
                BeanUtil.copyProperties(e, sysDictVo);
                result.add(sysDictVo);
            });
        }
        return result;
    }

    @Override
    public Sys_dict getByCode(String dictCode) {
        if (StringUtils.isEmpty(dictCode)) {
            throw new AppException("缺少请求参数！");
        }
        Sys_dict sysDict = this.fetch(Cnd.where(Sys_dict::getCode, "=", dictCode));
        return sysDict;
    }

    private List<SysDictVO> getAllChildRens(Sys_dict sysDict) {
        // 查询全部数据
        Cnd cnd = Cnd.NEW();
        cnd.getOrderBy().asc(Sys_dict::getLocation);
        cnd.where().andEquals(Sys_dict::isDisabled, false);
        List<Sys_dict> allList = this.query(cnd);
        List<SysDictVO> sysDictVOS = copyDictList(allList);
        SysDictVO sysDictVo = new SysDictVO();
        BeanUtil.copyProperties(sysDict, sysDictVo);
        List<SysDictVO> children = buildSysDict(sysDictVo, sysDictVOS);
        while (true) {
            if (children.size() == 0) {
                break;
            }
            List<SysDictVO> list = new ArrayList<>();
            for (SysDictVO child : children) {
                List<SysDictVO> children1 = buildSysDict(child, sysDictVOS);
                if (children1.size() > 0) {
                    list.addAll(children1);
                }
            }
            if (list.size() == 0) {
                break;
            }
            children = list;
        }
        return sysDictVo.getChildren();
    }

    private List<SysDictVO> buildSysDict(SysDictVO sysDict, List<SysDictVO> allList) {
        // 1 取出所有的孩子
        List<SysDictVO> children = allList.stream().filter(e -> sysDict.getId().equals(e.getParentId()))
                .sorted(Comparator.comparing(SysDictVO::getCreatedAt))
                .collect(Collectors.toList());
        if (children.size() == 0) {
            return Collections.emptyList();
        }
        sysDict.setChildren(children);
        // 2 检查孩子是否存在子孩子
        List<SysDictVO> childrens = children.stream().filter(Sys_dict::isHasChildren).collect(Collectors.toList());
        if (childrens.size() > 0) {
            return childrens;
        }
        return Collections.emptyList();
    }

    private List<SysDictVO> copyDictList(List<Sys_dict> list) {
        List<SysDictVO> res = new ArrayList<>();
        for (Sys_dict sysDict : list) {
            SysDictVO sysDictVO = new SysDictVO();
            BeanUtil.copyProperties(sysDict, sysDictVO);
            res.add(sysDictVO);
        }
        return res;
    }

    @Override
    public void updateDict(Sys_dict dict) {
        // 1 检查是否存在字典编码
        if (StringUtils.isEmpty(dict.getId())) {
            throw new AppException("字典id不能为空！");
        }
        if (StringUtils.isEmpty(dict.getCode())) {
            throw new AppException("字典编码不能为空！");
        }
        Sys_dict sysDict = this.fetch(Cnd.where(Sys_dict::getCode, "=", dict.getCode()));
        if (sysDict != null) {
            if (!sysDict.getId().equals(dict.getId())) {
                throw new AppException("该字典编码已被使用，请重新输入！");
            }
        }
        dict.setUpdatedBy(SecurityUtil.getUserId());
        dict.setUpdatedAt(System.currentTimeMillis());
        this.updateIgnoreNull(dict);
        this.cacheClear();
    }

    @Override
    public List<Sys_dict> batchQueryByCodes(List<String> dictCodes) {
        Cnd cnd = Cnd.NEW();
        SqlExpressionGroup where = cnd.where();
        where.andIn(Sys_dict::getCode, dictCodes.toArray(new String[0]))
                .andEquals(Sys_dict::isDisabled, false);
        cnd.getOrderBy().asc(Sys_dict::getLocation);
        return this.query(cnd);
    }

    @Override
    public JSONObject listDictByCodes(List<String> dictCodes) {
        JSONObject result = new JSONObject();
        // 1 处理特殊的字典 有子孙级的字典
        List<String> grandchildCode = DictComponent.getGrandchildCode();
        for (String code : grandchildCode) {
            Optional<String> optional = dictCodes.stream().filter(e -> e.equals(code)).findFirst();
            if (optional.isEmpty()) {
                continue;
            }
            List<SysDictVO> alls = listDictByCode(code);
            result.put(code, alls);
            dictCodes.remove(code);
        }
        if (dictCodes.size() == 0) {
            return result;
        }
        // 2 没有子孙级的数据
        List<Sys_dict> dictList = batchQueryByCodes(dictCodes);
        // 取出所有的id
        List<String> parentIds = dictList.stream().map(Sys_dict::getId).collect(Collectors.toList());
        // 按照父级id查询所有的子集数据
        Cnd cnd1 = Cnd.NEW();
        SqlExpressionGroup where1 = cnd1.where();
        where1.andIn(Sys_dict::getParentId, parentIds.toArray(new String[0]))
                .andEquals(Sys_dict::isDisabled, false);
        cnd1.getOrderBy().asc(Sys_dict::getLocation);
        List<Sys_dict> sysDicts = this.query(cnd1);
        for (String parentId : parentIds) {
            Sys_dict sysDict = dictList.stream().filter(e -> e.getId().equals(parentId)).findFirst().get();
            List<Sys_dict> collect = sysDicts.stream().filter(e -> e.getParentId().equals(parentId)).collect(Collectors.toList());
            result.put(sysDict.getCode(), collect);
        }
        return result;
    }

    @Override
    public List<Sys_dict> listChildRen(String parentId) {
        Cnd cnd1 = Cnd.NEW();
        SqlExpressionGroup where1 = cnd1.where();
        where1.andEquals(Sys_dict::getParentId, parentId)
                .andEquals(Sys_dict::isDisabled, false);
        cnd1.getOrderBy().asc(Sys_dict::getLocation);
        return this.query(cnd1);
    }

    @Override
    public List<Sys_dict> listDictChildByName(String dictName, String code, boolean isCounty) {
        List<String> parentIds = Lists.newArrayList();
        if (!isCounty) {
            if (StringUtils.isEmpty(dictName)) {
                throw new AppException("缺少请求参数！");
            }
            Cnd cnd = Cnd.where(Sys_dict::getName, "=", dictName);
            if (StringUtils.isNotBlank(code)) {
                String[] codes = code.split(",");
                SqlExpressionGroup sqlExpressionGroup = new SqlExpressionGroup();
                for (String item : codes) {
                    sqlExpressionGroup.or(Sys_dict::getCode, "like", "%" + item + "%");
                }
                cnd.and(sqlExpressionGroup);
            }
            Sys_dict sysDict = this.fetch(cnd);
            if (sysDict == null) {
                log.info("SysDictServiceImpl.listDictChildByName未查询到相关字典数据，dictName：{}，code:{}", dictName, code);
                return Lists.newArrayList();
            }
            parentIds.add(sysDict.getId());
        } else {
            //街道级别查询所有配置社区下的小区
            Cnd cnd = Cnd.where(Sys_dict::getCode, "like", "gs_community%");
            List<Sys_dict> sysDicts = this.query(cnd);
            parentIds = sysDicts.stream().map(Sys_dict::getId).collect(Collectors.toList());
        }
        List<Sys_dict> list = this.query(Cnd.where(Sys_dict::getParentId, "in", parentIds).orderBy(Sys_dict::getLocation, "asc"));
        return list;
    }

    @Override
    public String getCode(String parentCode, String name) {
        Sys_dict dict = this.fetch(Cnd.where("code", "=", parentCode));
        if (dict == null) return null;
        Cnd cnd = Cnd.NEW();
        cnd.and(Sys_dict::getName, "=", name);
        cnd.and(Sys_dict::getParentId, "=", dict.getId());
        Sys_dict sysDict = this.fetch(cnd);
        if (sysDict == null) return null;
        return sysDict.getCode();
    }

    @Override
    public Sys_dict getDictByLikeCode(String code) {
        if (StringUtils.isEmpty(code)) {
            throw new ServiceException("缺少请求参数！");
        }
        return this.fetch(Cnd.where(Sys_dict::getCode, "like", "%"+code));
    }

    private void popularChildren(SysDictVO parentDict) {
        List<Sys_dict> subList = getSubListById(parentDict.getId());
        if (subList.size() > 0) {
            List<SysDictVO> resultList = org.apache.commons.compress.utils.Lists.newArrayList();

            for (Sys_dict sysDict : subList) {
                SysDictVO vo = new SysDictVO();
                BeanUtil.copyProperties(sysDict, vo);
                vo.setLabel(sysDict.getName());
                popularChildren(vo);

                resultList.add(vo);
            }

            parentDict.setChildren(resultList);
        }
    }

    private List<String> getAllSubId(String parentId) {
        List<String> allSubId = Lists.newArrayList();
        Cnd cnd = Cnd.NEW();
        cnd.and("parentid", "=", parentId);
        List<Sys_dict> subDictList = query(cnd);
        allSubId.addAll(subDictList.stream().map(Sys_dict::getId).collect(Collectors.toList()));
        if (subDictList.size() > 0) {
            for (Sys_dict subDict : subDictList) {
                allSubId.addAll(getAllSubId(subDict.getId()));
            }
        }

        return allSubId;
    }
}
